package org.budo.dubbo.protocol.async;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.budo.dubbo.protocol.async.util.ExporterUtil;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.rpc.Exporter;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;
import com.alibaba.dubbo.rpc.RpcException;

/**
 * 存储服务暴露配置信息
 * 
 * @author lmw
 */
public class BudoAsyncDubboProtocol implements Protocol {
    private static final Logger log = LoggerFactory.getLogger(BudoAsyncDubboProtocol.class);

    /**
     * 默认序列化方式为Java
     */
    public static final String DEFAULT_SERIALIZATION = "java";

    private static BudoAsyncDubboProtocol _INSTANCE = null;

    private final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>();

    /**
     * 如果有多个实例，合并配置数据
     */
    public BudoAsyncDubboProtocol() {
        synchronized (BudoAsyncDubboProtocol.class) {
            if (null == _INSTANCE) { // 如果有多个实例，合并配置数据
                _INSTANCE = this;
                return;
            }

            log.warn("#32 more than 1 instance of BudoAsyncDubboProtocol, _INSTANCE=" + _INSTANCE + ", this=" + this);
            this.exporterMap.putAll(_INSTANCE.getExporterMap());

            _INSTANCE = this;
        }
    }

    public static BudoAsyncDubboProtocol getInstance() {
        return _INSTANCE;
    }

    /**
     * 消费消息
     */
    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        String exporterKey = ExporterUtil.exporterKey(invoker);

        @SuppressWarnings("unchecked")
        Exporter<T> exporter = (Exporter<T>) this.getExporterMap().get(exporterKey);
        if (null != exporter) {
            log.warn("#65 export, exporter exists, return, exporter=" + exporter + ", invoker=" + invoker);
            return exporter;
        }

        Exporter<T> newExporter = new BudoAsyncDubboExporter<T>(invoker, this);
        this.getExporterMap().put(exporterKey, newExporter);
        return newExporter;
    }

    /**
     * Invoker 发消息
     */
    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        return new BudoAsyncDubboInvoker<T>(type, url);
    }

    public Map<String, Exporter<?>> getExporterMap() {
        return this.exporterMap;
    }

    @Override
    public int getDefaultPort() {
        return 12345;
    }

    @Override
    public void destroy() {
        log.info("#80 destroy, this=" + this);
    }

    @Override
    public String toString() {
        return super.toString() + ", exporterMap=" + this.getExporterMap();
    }
}